package com.ruoyi.datastatistics.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.ruoyi.basedata.mapper.DwAreasMapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.PageUtil;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.datastatistics.domain.MeterHistoryData;
import com.ruoyi.datastatistics.domain.TerminalsFreezeXb;
import com.ruoyi.datastatistics.mapper.TerminalXbStatisticAnalysisMapper;
import com.ruoyi.datastatistics.mapper.TerminalsFreezeXbMapper;
import com.ruoyi.datastatistics.model.MeterReadingRateResultModel;
import com.ruoyi.datastatistics.service.ITerminalXbStatisticAnalysisService;
import com.ruoyi.datastatistics.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class TerminalXbStatisticAnalysisServiceImpl implements ITerminalXbStatisticAnalysisService {

    @Autowired
    private TerminalsFreezeXbMapper terminalsFreezeXbMapper;

    @Autowired
    private DwAreasMapper areasMapper;

    @Autowired
    private TerminalXbStatisticAnalysisMapper terminalXbStatisticAnalysisMapper;
//    @Override
//    public Map<String, List<DosageStatistics>> sumDayOrMonth(String frozenType, String areaId, String beginTime, String endTime) {
//        List<DwAreas> dwAreas = areasMapper.selectList(new LambdaQueryWrapper<DwAreas>()
//                .eq(DwAreas::getParentId, areaId));
//        Map<String,List<DosageStatistics>> map = new HashMap<>();
//        dwAreas.forEach(dwAreas1 -> {
//            List<DosageStatistics> dosageStatisticsList = terminalsFreezeXbMapper.selectDosageStatistics(frozenType, dwAreas1.getAreaCode(),beginTime,endTime);
//            map.put(dwAreas1.getAreaName(),dosageStatisticsList);
//        });
//        return map;
//    }

    @Override
    public List<DayOrMonthDosageStatistics> DayOrMonth(XbStatisticAnalysisReq req) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("sheetsCode", req.getSheetsCode());
        paramMap.put("frozenType", req.getFrozenType());
        paramMap.put("beginTime", req.getBeginTime());
        paramMap.put("endTime", req.getEndTime());
        paramMap.put("userId", req.getUserId());
        paramMap.put("userName", req.getUserName());
        paramMap.put("terminalId", req.getTerminalId());
        paramMap.put("communicateAddress", req.getCommunicateAddress());
        paramMap.put("locationNb",req.getLocationNb());
        SysUser user = SecurityUtils.getLoginUser().getUser();
        if (user != null) {
            if (!Objects.equals(user.getSystemFlag(), Constants.SYS_FLAG_ADMIN)) {
                Long userId = user.getUserId();
                paramMap.put("sysUserId",userId);
            }
            if (Objects.equals(user.getSystemFlag(), Constants.SYS_FLAG_NORMAL_USER)) {
                paramMap.put("tenantId",user.getTenantId());
            }
        }
        return terminalXbStatisticAnalysisMapper.DayOrMonth(paramMap);
    }

    @Override
    public List<DayOrMonthDosageStatistics> elecDayOrMonth(XbStatisticAnalysisReq req) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("sheetsCode", req.getSheetsCode());
        paramMap.put("frozenType", req.getFrozenType());
        paramMap.put("beginTime", req.getBeginTime());
        paramMap.put("endTime", req.getEndTime());
        paramMap.put("userId", req.getUserId());
        paramMap.put("userName", req.getUserName());
        paramMap.put("terminalId", req.getTerminalId());
        paramMap.put("communicateAddress", req.getCommunicateAddress());
        paramMap.put("locationNb",req.getLocationNb());
        SysUser user = SecurityUtils.getLoginUser().getUser();
        if (user != null) {
            if (!Objects.equals(user.getSystemFlag(), Constants.SYS_FLAG_ADMIN)) {
                Long userId = user.getUserId();
                paramMap.put("sysUserId",userId);
            }
            if (Objects.equals(user.getSystemFlag(), Constants.SYS_FLAG_NORMAL_USER)) {
                paramMap.put("tenantId",user.getTenantId());
            }
        }
        return terminalXbStatisticAnalysisMapper.elecDayOrMonth(paramMap);
    }

    @Override
    public List<DayOrMonthDosageStatistics> HourOrDayOrMonthOrRoundList(XbStatisticAnalysisReq req) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("sheetsCode", req.getSheetsCode());
        paramMap.put("frozenType", req.getFrozenType());
        paramMap.put("beginTime", req.getBeginTime());
        paramMap.put("endTime", req.getEndTime());
        paramMap.put("userId", req.getUserId());
        paramMap.put("userName", req.getUserName());
        paramMap.put("terminalId", req.getTerminalId());
        paramMap.put("communicateAddress", req.getCommunicateAddress());
        paramMap.put("locationNb",req.getLocationNb());
        SysUser user = SecurityUtils.getLoginUser().getUser();
        if (user != null) {
            if (!Objects.equals(user.getSystemFlag(), Constants.SYS_FLAG_ADMIN)) {
                Long userId = user.getUserId();
                paramMap.put("sysUserId",userId);
            }
            if (Objects.equals(user.getSystemFlag(), Constants.SYS_FLAG_NORMAL_USER)) {
                paramMap.put("tenantId",user.getTenantId());
            }
        }
//        terminalXbStatisticAnalysisMapper.HourOrDayOrMonthOrRoundList(paramMap);
//        terminalXbStatisticAnalysisMapper.DayOrMonth(paramMap);
        List<DayOrMonthDosageStatistics> list = terminalXbStatisticAnalysisMapper.HourOrDayOrMonth(paramMap);
        if (CollectionUtil.isEmpty(list)){
            return Collections.emptyList();
        }
        List<String> locationNbs = list.stream().map(DayOrMonthDosageStatistics::getLocationNb).collect(Collectors.toList());
        req.setLocationNbList(locationNbs);
        List<TerminalsFreezeXb> terminalsFreezeXbList = new ArrayList<>();
        if ("hour".equals(req.getFrozenType())){
            String beginTime = req.getBeginTime().substring(0, 10);
            req.setBeginTime(beginTime + " 00");
            req.setEndTime(beginTime + " 23");
            terminalsFreezeXbList = terminalXbStatisticAnalysisMapper.selectHourOrDayOrMonthList(req);
            convertResultDosageStatistics(list, terminalsFreezeXbList, req);
        }else if ("day".equals(req.getFrozenType())){
            String beginTime = req.getBeginTime().substring(0, 7);
            req.setBeginTime(beginTime + "-01");
            req.setEndTime(beginTime + "-31");
            terminalsFreezeXbList = terminalXbStatisticAnalysisMapper.selectHourOrDayOrMonthList(req);
            convertResultDosageStatistics(list, terminalsFreezeXbList, req);
        }else if ("month".equals(req.getFrozenType())){
            String beginTime = req.getBeginTime().substring(0, 4);
            req.setBeginTime(beginTime + "-01");
            req.setEndTime(beginTime + "-12");
            terminalsFreezeXbList = terminalXbStatisticAnalysisMapper.selectHourOrDayOrMonthList(req);
            convertResultDosageStatistics(list, terminalsFreezeXbList, req);
        } else if ("period".equals(req.getFrozenType())) {
            req.setFrozenType("hour");
            terminalsFreezeXbList = terminalXbStatisticAnalysisMapper.selectPeriodList(req);
            req.setFrozenType("period");
            convertResultDosageStatistics(list, terminalsFreezeXbList, req);
        }

        return list;
    }

    private void convertResultDosageStatistics(List<DayOrMonthDosageStatistics> list, List<TerminalsFreezeXb> terminalsFreezeXbList, XbStatisticAnalysisReq req) {
        DecimalFormat decimalFormat = new DecimalFormat("0.00");
        if ("hour".equals(req.getFrozenType())){
            for (DayOrMonthDosageStatistics statistics : list) {
                HourCumulativeFlow hourCumulativeFlow = new HourCumulativeFlow();
                Map<String, BigDecimal> hourMap = terminalsFreezeXbList.stream()
                        .filter(terminalsFreezeXb -> terminalsFreezeXb.getLocationNb().equals(statistics.getLocationNb()))
                        .collect(Collectors.toMap(
                                TerminalsFreezeXb::getFreezeTime,
                                TerminalsFreezeXb::getCumulativeFlow,
                                (oldValue, newValue) -> newValue
                        ));
                for (int i = 0; i <= 23; i++) {
                    String hourStr = String.format("%02d", i);
                    String s = req.getBeginTime().substring(0, 10) + " ";
                    String mapKey =  s + hourStr;
                    String setterMethodName = "setHour" + hourStr;
                    BigDecimal flowValue = hourMap.getOrDefault(mapKey, BigDecimal.ZERO);
                    String formattedValue = decimalFormat.format(flowValue);
                    try {
                        Method setter = HourCumulativeFlow.class.getMethod(setterMethodName, String.class);
                        setter.invoke(hourCumulativeFlow, formattedValue);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
                statistics.setHourCumulativeFlow(hourCumulativeFlow);
            }
        }else if ("day".equals(req.getFrozenType())){
            for (DayOrMonthDosageStatistics statistics : list) {
                DayCumulativeFlow dayCumulativeFlow = new DayCumulativeFlow();
                Map<String, BigDecimal> hourMap = terminalsFreezeXbList.stream()
                        .filter(terminalsFreezeXb -> terminalsFreezeXb.getLocationNb().equals(statistics.getLocationNb()))
                        .collect(Collectors.toMap(
                                TerminalsFreezeXb::getFreezeTime,
                                TerminalsFreezeXb::getCumulativeFlow,
                                (oldValue, newValue) -> newValue
                        ));
                for (int i = 1; i <= 31; i++) {
                    String dayStr = String.format("%02d", i);
                    String s = req.getBeginTime().substring(0, 7) + "-";
                    String mapKey =  s + dayStr;
                    String setterMethodName = "setDay" + dayStr;
                    BigDecimal flowValue = hourMap.getOrDefault(mapKey, BigDecimal.ZERO);
                    String formattedValue = decimalFormat.format(flowValue);
                    try {
                        Method setter = DayCumulativeFlow.class.getMethod(setterMethodName, String.class);
                        setter.invoke(dayCumulativeFlow, formattedValue);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
                statistics.setDayCumulativeFlow(dayCumulativeFlow);
            }
        }else if ("month".equals(req.getFrozenType())){
            for (DayOrMonthDosageStatistics statistics : list) {
                MonthCumulativeFlow monthCumulativeFlow = new MonthCumulativeFlow();
                Map<String, BigDecimal> hourMap = terminalsFreezeXbList.stream()
                        .filter(terminalsFreezeXb -> terminalsFreezeXb.getLocationNb().equals(statistics.getLocationNb()))
                        .collect(Collectors.toMap(
                                TerminalsFreezeXb::getFreezeTime,
                                TerminalsFreezeXb::getCumulativeFlow,
                                (oldValue, newValue) -> newValue
                        ));
                for (int i = 1; i <= 12; i++) {
                    String monthStr = String.format("%02d", i);
                    String s = req.getBeginTime().substring(0, 4) + "-";
                    String mapKey =  s + monthStr;
                    String setterMethodName = "setDay" + monthStr;
                    BigDecimal flowValue = hourMap.getOrDefault(mapKey, BigDecimal.ZERO);
                    String formattedValue = decimalFormat.format(flowValue);
                    try {
                        Method setter = MonthCumulativeFlow.class.getMethod(setterMethodName, String.class);
                        setter.invoke(monthCumulativeFlow, formattedValue);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
                statistics.setMonthCumulativeFlow(monthCumulativeFlow);
            }
        } else if ("period".equals(req.getFrozenType())) {
            for (DayOrMonthDosageStatistics statistics : list) {
                Map<String, BigDecimal> periodMap = terminalsFreezeXbList.stream()
                        .filter(terminalsFreezeXb -> terminalsFreezeXb.getLocationNb().equals(statistics.getLocationNb()))
                        .collect(Collectors.toMap(
                                TerminalsFreezeXb::getFreezeTime,
                                TerminalsFreezeXb::getCumulativeFlow,
                                (oldValue, newValue) -> newValue
                        ));
                statistics.setStartReading(periodMap.getOrDefault(req.getBeginTime(),BigDecimal.ZERO));
                statistics.setEndReading(periodMap.getOrDefault(req.getEndTime(),BigDecimal.ZERO));
                statistics.setCumulativeFlow(decimalFormat.format(statistics.getEndReading().subtract(statistics.getStartReading())));
            }
        }
    }

    @Override
    public String sumYear(String year) {
        return null;
    }

    @Override
    public List<MeterHistoryData> oneTerminal(String roomId, String[] readDates) {
        return terminalXbStatisticAnalysisMapper.oneTerminal(roomId, readDates);
    }

    @Override
    public List<MeterHistoryData> multiTerminal(String[] roomIds, String readDate) {
        return terminalXbStatisticAnalysisMapper.multiTerminal(roomIds, readDate);
    }

    @Override
    public List<DosageStatistics> areaDosage(XbStatisticAnalysisReq req) {
        return terminalXbStatisticAnalysisMapper.areaDosage(req);
    }

    @Override
    public List<BlankDosageStatistics> blankDosage(String sheetsCode, String beginTime, String endTime, String orderByColumn, String isAsc) {
        List<BlankDosageStatistics> blankDosageStatisticsList = terminalXbStatisticAnalysisMapper.blankDosage(sheetsCode.split(","), beginTime, endTime);
        int allRoomSize = blankDosageStatisticsList.stream().mapToInt(BlankDosageStatistics::getFamilyNum).reduce(0, Integer::sum);
        NumberFormat nt = NumberFormat.getPercentInstance();
        nt.setMinimumFractionDigits(2);
        blankDosageStatisticsList.forEach(blankDosageStatistics -> {
            String blankRate = nt.format((double) blankDosageStatistics.getBlankDosageNum() / allRoomSize);
            String notBlankRate = nt.format((double) blankDosageStatistics.getNotBlankDosageNum() / allRoomSize);
            blankDosageStatistics.setBlankRate(blankRate);
            blankDosageStatistics.setNotBlankRate(notBlankRate);
        });

        Comparator<BlankDosageStatistics> comparator = Comparator.comparing(BlankDosageStatistics::getSheetsCode);
        if ("sheetsName".equals(orderByColumn)) {
            comparator = Comparator.comparing(BlankDosageStatistics::getSheetsName);
        }
        if ("familyNum".equals(orderByColumn)) {
            comparator = Comparator.comparing(BlankDosageStatistics::getFamilyNum);
        }
        if ("blankDosageNum".equals(orderByColumn)) {
            comparator = Comparator.comparing(BlankDosageStatistics::getBlankDosageNum);
        }
        if ("notBlankDosageNum".equals(orderByColumn)) {
            comparator = Comparator.comparing(BlankDosageStatistics::getNotBlankDosageNum);
        }
        if ("descending".equals(isAsc)) {
            comparator = comparator.reversed();
        }

        blankDosageStatisticsList.sort(comparator);

        return blankDosageStatisticsList;
    }

    @Override
    public List<DosageRangeStatistics> rangeDosage(String sheetsCode, String beginTime, String endTime) {
        return terminalXbStatisticAnalysisMapper.rangeDosage(sheetsCode, beginTime, endTime);
    }

    @Override
    public TableDataInfo dosageUprush(XbStatisticAnalysisReq req, Integer pageSize, Integer pageNum) {

        SysUser user = SecurityUtils.getLoginUser().getUser();
        if (user != null) {
            if (!Objects.equals(user.getSystemFlag(), Constants.SYS_FLAG_ADMIN)) {
                Long userId = user.getUserId();
                req.setSysUserId(userId);
            }
            if (Objects.equals(user.getSystemFlag(), Constants.SYS_FLAG_NORMAL_USER)) {
                req.setTenantId(user.getTenantId());
            }
        }


        List<MonthDosageGrowthRatio> monthDosageGrowthRatios = terminalXbStatisticAnalysisMapper.dosageUprush(req);

        Comparator<MonthDosageGrowthRatio> comparator = Comparator.comparing(MonthDosageGrowthRatio::getSheetsCode);
        if ("sheetsName".equals(req.getOrderByColumn())) {
            comparator = Comparator.comparing(MonthDosageGrowthRatio::getSheetsName);
        }
        if ("userId".equals(req.getOrderByColumn())) {
            comparator = Comparator.comparing(MonthDosageGrowthRatio::getUserId);
        }
        if ("userName".equals(req.getOrderByColumn())) {
            comparator = Comparator.comparing(MonthDosageGrowthRatio::getUserName);
        }
        if ("userName".equals(req.getOrderByColumn())) {
            comparator = Comparator.comparing(MonthDosageGrowthRatio::getUserName);
        }
        if ("installAddress".equals(req.getOrderByColumn())) {
            comparator = Comparator.comparing(MonthDosageGrowthRatio::getInstallAddress);
        }
        if ("terminalId".equals(req.getOrderByColumn())) {
            comparator = Comparator.comparing(MonthDosageGrowthRatio::getTerminalId);
        }
        if ("communicateAddress".equals(req.getOrderByColumn())) {
            comparator = Comparator.comparing(MonthDosageGrowthRatio::getCommunicateAddress);
        }
        if ("comparisonDosage".equals(req.getOrderByColumn())) {
            comparator = Comparator.comparing(MonthDosageGrowthRatio::getComparisonDosage);
        }
        if ("nowDosage".equals(req.getOrderByColumn())) {
            comparator = Comparator.comparing(MonthDosageGrowthRatio::getNowDosage);
        }
        if ("rate".equals(req.getOrderByColumn())) {
            comparator = Comparator.comparingDouble(item -> item.getRate() == null || item.getRate().equals("-") ? -999999D : Double.parseDouble(item.getRate()));
        }
        if ("descending".equals(req.getIsAsc())) {
            comparator = comparator.reversed();
        }

        monthDosageGrowthRatios.sort(comparator);

        if (req.getComparisonRate() == null || req.getComparisonRate().equals("null")) {
            TableDataInfo tableDataInfo = new TableDataInfo();
            tableDataInfo.setTotal(monthDosageGrowthRatios.size());
            tableDataInfo.setRows(PageUtil.startPage(monthDosageGrowthRatios, pageNum, pageSize));
            tableDataInfo.setCode(200);
            return tableDataInfo;
        }

        BigDecimal flag = new BigDecimal(req.getComparisonRate());
        switch (req.getSymbol()) {
            case 1:
                monthDosageGrowthRatios = monthDosageGrowthRatios.stream().filter(monthDosageGrowthRatio -> {
                            if (StrUtil.isEmpty(monthDosageGrowthRatio.getRate()) || monthDosageGrowthRatio.getRate().equals("-")) {
                                return false;
                            }
                            return new BigDecimal(monthDosageGrowthRatio.getRate()).compareTo(flag) > -1;
                        }
                ).collect(Collectors.toList());
                break;
            case 2:
                monthDosageGrowthRatios = monthDosageGrowthRatios.stream().filter(monthDosageGrowthRatio -> {
                            if (StrUtil.isEmpty(monthDosageGrowthRatio.getRate()) || monthDosageGrowthRatio.getRate().equals("-")) {
                                return false;
                            }
                            return new BigDecimal(monthDosageGrowthRatio.getRate()).compareTo(flag) < 1;
                        }
                ).collect(Collectors.toList());
                break;
            case 3:
                monthDosageGrowthRatios = monthDosageGrowthRatios.stream().filter(monthDosageGrowthRatio -> {
                            if (StrUtil.isEmpty(monthDosageGrowthRatio.getRate()) || monthDosageGrowthRatio.getRate().equals("-")) {
                                return false;
                            }
                            return new BigDecimal(monthDosageGrowthRatio.getRate()).compareTo(flag) == 0;
                        }
                ).collect(Collectors.toList());
                break;
        }

        TableDataInfo tableDataInfo = new TableDataInfo();
        tableDataInfo.setTotal(monthDosageGrowthRatios.size());
        tableDataInfo.setRows(PageUtil.startPage(monthDosageGrowthRatios, pageNum, pageSize));
        tableDataInfo.setCode(200);
        return tableDataInfo;
    }
}
